package com.geqian.web.chat;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.geqian.web.entity.User;
import com.geqian.web.mapper.UserMapper;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @author geqian
 * @date 9:46 2022/10/11
 */
@Component
@ServerEndpoint(value = "/chat/{username}", configurator = WebSocketResponseConfigurator.class)
public class WebSocketServer {

    private static UserMapper userMapper;

    /**
     * 当前在线连接数
     */
    private static final AtomicInteger onlineCount = new AtomicInteger(0);
    /**
     * concurrentHashMap分段锁，用来存放每个客户端对应的Websocket对象。
     */
    private static ConcurrentMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
    /**
     * 与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    private Session session;

    /**
     * 用户唯一标识
     */
    private String username;


    /**
     * 建立连接时调用
     *
     * @param session
     * @param username
     */
    @OnOpen
    public void onOpen(@PathParam("username") String username, Session session) throws Exception {
        this.session = session;
        this.username = username;
        webSocketMap.put(username, this);

        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(User::getUserName, webSocketMap.keySet());
        List<UserBaseInfo> userList = userMapper.selectList(wrapper).stream()
                .map(user -> new UserBaseInfo(user.getUserName(), user.getAvatar()))
                .collect(Collectors.toList());
        this.sendMessageAll(JSON.toJSONString(new Message(0, null, null, false, userList)));
    }


    /**
     * 接收到客服端发送的消息时调用
     *
     * @param message
     * @param session
     */
    @OnMessage
    public void onMessage(String message, Session session) throws Exception {
        Message messageObj = JSONObject.parseObject(message, Message.class);
        String sender = messageObj.getSender();
        String receiver = messageObj.getReceiver();
        WebSocketServer webSocketServer = webSocketMap.get(receiver);
        messageObj.setReceiver(sender);
        messageObj.setSender(receiver);
        webSocketServer.sendMessage(message);
    }

    /**
     * 连接关闭时调用
     *
     * @param session
     * @param closeReason
     */
    @OnClose
    public void onClose(Session session, CloseReason closeReason) throws Exception {
        webSocketMap.remove(username);
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        Set<String> usernames = webSocketMap.keySet();
        if (!CollectionUtils.isEmpty(usernames)) {
            wrapper.in(User::getUserName, usernames);
            List<UserBaseInfo> userList = userMapper.selectList(wrapper).stream()
                    .map(user -> new UserBaseInfo(user.getUserName(), user.getAvatar()))
                    .collect(Collectors.toList());
            this.sendMessageAll(JSON.toJSONString(new Message(0, null, null, false, userList)));
        }
    }


    /**
     * 发生协议错误时触发的事件
     *
     * @param session
     * @param throwable
     */
    @OnError
    public void onError(Session session, Throwable throwable) {

    }


    public void sendMessage(String message) {
        try {
            this.session.getBasicRemote().sendText(message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 群发
     *
     * @param message
     */
    public void sendMessageAll(String message) {
        Collection<WebSocketServer> webSocketServers = webSocketMap.values();
        for (WebSocketServer webSocketServer : webSocketServers) {
            webSocketServer.sendMessage(message);
        }
    }


    /**
     * 获取在线人数
     *
     * @return
     */
    public static AtomicInteger getOnlineCount() {
        return WebSocketServer.onlineCount;
    }


    /**
     * 在线人数增加
     */
    public static void incrementCount() {
        WebSocketServer.onlineCount.getAndIncrement();
    }

    /**
     * 在线人数减少
     */
    public static void decrementCount() {
        WebSocketServer.onlineCount.getAndDecrement();
    }

    /**
     * 获取指定的 WebSocket对象
     *
     * @param username
     * @return
     */
    public static WebSocketServer getWebSocketServer(String username) {
        return webSocketMap.get(username);
    }


    /**
     * 获取全部 WebSocket对象
     *
     * @return
     */
    public static Map<String, WebSocketServer> getWebSocketMap() {
        return webSocketMap;
    }


    @Resource
    public void setUserMapper(UserMapper userMapper) {
        WebSocketServer.userMapper = userMapper;
    }
}